import options, { STORE } from './options'

export { STORE } from './options'

export enum MODEL {
  readwrite = 'readwrite',
  readonly = 'readonly',
  versionchange = 'versionchange'
}

export class IndexedDB {
  // 饿汉模式
  private static _ins: IndexedDB = new IndexedDB()
  private _instance: IDBDatabase = {} as IDBDatabase
  private _db: IDBFactory = window.indexedDB
  private _request?: IDBOpenDBRequest

  public static getInstance(): IndexedDB {
    return IndexedDB._ins
  }

  private constructor() {
    this._request = this._db.open(options.name, options.version)
    // 打开数据库成功
    this._request.onsuccess = (e: any) => {
      this._instance = e.target.result
    }
    // 打开数据库失败
    this._request.onerror = () => {
      console.error('打开数据库失败')
    }
    // 第一次打开成功后或者版本有变化
    this._request.onupgradeneeded = (e: any) => {
      this._instance = e.target.result
      // 创建表对象
      for (const key in options.tables) {
        const opts = options.tables[key]
        const request = this._instance.createObjectStore(key, {
          keyPath: opts.keyPath,
          autoIncrement: opts.autoIncrement
        })
        opts.columns.map((column: any) => {
          request.createIndex(column.key, column.key, column.options)
        })
      }
    }
  }

  // 关闭数据库
  public closeDB() {
    this._instance.close()
  }

  // 删除数据库
  public deleteDB(name: STORE) {
    this._db.deleteDatabase(name)
  }

  // 新增一条数据
  public addData(storeName: STORE, value: any) {
    const store = this.getStore(storeName, MODEL.readwrite)
    store.add(value)
  }

  // 根据键值获取一条数据
  public getDataByKey(storeName: STORE, key: string | number| Date | ArrayBufferView | ArrayBuffer | IDBArrayKey | IDBKeyRange) {
    const store = this.getStore(storeName, MODEL.readwrite)
    const request = store.get(key)
    return new Promise<any>((resolve, reject) => {
      request.onsuccess = (e: any) => {
        resolve(e.target.result)
      }
      request.onerror = () => {
        reject(new Error('操作失败'))
      }
    })
  }

  // 更新一条数据
  public updateDataByKey(storeName: STORE, value: any) {
    const store = this.getStore(storeName, MODEL.readwrite)
    const request = store.put(value)
    return new Promise<any>((resolve, reject) => {
      request.onsuccess = (e: any) => {
        resolve(e.target.result)
      }
      request.onerror = () => {
        reject(new Error('操作失败'))
      }
    })
  }

  // 删除一条数据
  public deleteDataByKey(storeName: STORE, key: string | number | Date | IDBKeyRange | IDBArrayKey) {
    const store = this.getStore(storeName, MODEL.readwrite)
    const request = store.delete(key)
    return new Promise((resolve, reject) => {
      request.onsuccess = () => {
        resolve()
      }
      request.onerror = () => {
        reject(new Error('操作失败'))
      }
    })
  }

  // 清空数据表
  public clearStore(name: STORE | string) {
    const store = this.getStore(name, MODEL.readwrite)
    store.clear()
  }

  // 删除数据表
  public deleteStore(name: STORE | string) {
    this._instance.deleteObjectStore(name)
  }

  private getStore(name: STORE | string, model?: MODEL) {
    const transaction = this.getTransaction(name, model)
    const store = transaction.objectStore(name)
    return store
  }

  private getTransaction(name: STORE | string, model?: MODEL) {
    const transaction = this._instance.transaction(name, model)
    return transaction
  }
}
